package saer.send.now.channel;

import javax.servlet.http.HttpServletResponse;

import com.google.appengine.repackaged.org.json.JSONException;
import com.google.appengine.repackaged.org.json.JSONObject;

public class State {
    private static final int    WAITING_FOR_PEER = 0;
    private static final int    WAITING_FOR_SIZE = 3;
    private static final int    SENDING          = 4;
    private static final int    DONE             = 5;
    private static final int    ERROR            = 6;

    private static int          totalBytesSent   = 0;

    private long                bytesSent        = 0;
    private long                totalBytesToSend = 0;
    private int                 state            = WAITING_FOR_PEER;
    private String              msg;
    private HttpServletResponse resp;

    public State(HttpServletResponse resp) {
        this.resp = resp;
    }

    public synchronized void setTotalBytesToSend(int size) {
        this.state = SENDING;
        this.totalBytesToSend = size;
        resp.setContentLength(size);
    }

    public synchronized void startUpload() {
        this.state = WAITING_FOR_SIZE;
    }

    public synchronized void incBytesSent(int length) {
        this.bytesSent += length;
        totalBytesSent += length;

        if (this.bytesSent >= this.totalBytesToSend) {
            this.state = DONE;
        }
    }

    public synchronized int getBytesLeft() {
        return (int) (this.totalBytesToSend - this.bytesSent);
    }

    public synchronized void setError(String msg) {
        this.state = ERROR;
        this.msg = msg;
    }

    @Override
    public synchronized String toString() {
        StringBuilder sb = new StringBuilder("State: ");

        sb.append("bytesSent: ");
        sb.append(this.bytesSent);
        sb.append(", totalBytesToSend: ");
        sb.append(this.totalBytesToSend);
        sb.append(", state: ");
        sb.append(translateState(this.state));
        sb.append(", msg: ");
        sb.append(this.msg);

        return sb.toString();
    }

    public synchronized boolean isDone() {
        return this.state == DONE;
    }

    private static String translateState(int state) {
        switch (state) {
        case WAITING_FOR_PEER:
            return "WAITING_FOR_PEER";
        case WAITING_FOR_SIZE:
            return "WAITING_FOR_SIZE";
        case SENDING:
            return "SENDING";
        case DONE:
            return "DONE";
        case ERROR:
            return "ERROR";
        default:
            return "UNKNOWN";
        }
    }

    public synchronized String getStatus() {
        try {
            JSONObject status = new JSONObject();

            status.put("state", this.state);
            status.put("totalBytesToSend", this.totalBytesToSend);
            status.put("bytesSent", this.bytesSent);
            status.put("msg", this.msg);

            status.put("WAITING_FOR_PEER", WAITING_FOR_PEER);
            status.put("WAITING_FOR_SIZE", WAITING_FOR_SIZE);
            status.put("SENDING", SENDING);
            status.put("DONE", DONE);
            status.put("ERROR", ERROR);

            return status.toString();
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    public synchronized static String getTotalBytesSent() {
        try {
            JSONObject totalBytesSentObject = new JSONObject();
            totalBytesSentObject.put("totalBytesSent", totalBytesSent);
            return totalBytesSentObject.toString();
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }
}
